home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-09 | 4.9 KB | 172 lines | [TEXT/CWIE] |
- /*
- DrawGrating.c
-
- Quickly draws a grating (cos, sin, square, or missing fundamental) with a
- gaussian envelope in the current port, bounded by the supplied rect. The routine
- is accurate and takes advantage of even and odd symmetries for speed. It is not
- entirely general, e.g. orientation is restricted to vertical and horizontal.
-
- Squarewaves have an undefined value at zero crossings, e.g. at the origin, so I've
- shifted all the functions by a half pixel up and to the left.
-
- WARNING: To compile this routine you'll need the header files nr.h and nrutil.h,
- which are part of the Numerical Recipes in C, sold by Cambridge University Press
- for about $100. (See Advice document.) Furthermore, within nr.h, you should make
- sure that ANSI prototypes are enabled, since they provide the strictest and
- safest prototype information. Similarly, set your compiler to REQUIRE prototypes.
- The FLOAT type is my modification of the Numerical Recipes files, as explained in
- the "Numerical Recipes.doc" file in Notes. (Bosco Tjan reports that you need the
- current version, 2, since version 1 omits the lvector() function.)
-
- HISTORY:
- 11/2/94 dgp shrink by s->noiseCheckSize, since it will later be expanded by that amount.
- 3/26/95 dgp as requested by Manoj, there are now separate space constants along and across
- bars.
- 6/16/95 dgp replace "noiseCheckSize" by "signalCheckSize".
- 6/17/95 dgp changed "signalBounds" in first line to "stimulusBounds"
- 6/17/95 dgp eliminated all reference to s->signalContrast, since that applies to the
- entire sequence of images.
- */
- //#include "TextInNoise.h"
- #include "nr.h" /* prototypes of Numerical Recipes and definition of FLOAT */
- #include "nrutil.h"
- enum{kCosinewave=0,kSinewave,kSquarewave,kMissingFundamental};// gratingType
- typedef struct{
- FLOAT degreesPerPixel;
- FLOAT spatialFrequency,spaceConstantAlongBars,spaceConstantAcrossBars;
- Rect bounds;
- Point origin; // origin of the functions will be half a pixel up and to the left of this.
- int gratingType;
- int checkSize;
- Boolean vertical;
- int eAmplitude,eOffset;
- }GratingSpec;
- void DrawGrating(GratingSpec *g);
-
- #undef MAX
- #undef MIN
- #define MAX(a,b) ((a) > (b) ? (a) : (b))
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
-
- void DrawGrating(GratingSpec *g)
- {
- unsigned long *gratingPix;
- FLOAT *fX,*fXEnvelope,*fY,*fTemp,w,e1,b,dc,a;
- int iMax,width,fXSymmetry=0,fYSymmetry=0;
- enum{kEven=1,kOdd};
- Rect r;
- int i,j;
- int leftEdge,verticalOrigin;
-
- r=g->bounds;
- OffsetRect(&r,-g->origin.h,-g->origin.v);
- ShrinkRect(&r,g->checkSize,g->checkSize); // Shrink
- iMax=MAX(r.right,-r.left)-1;
- iMax=MAX(iMax,MAX(r.bottom,-r.top)-1);
- fX=vector(-iMax-1,iMax);
- fXEnvelope=vector(-iMax-1,iMax);
- fY=vector(-iMax-1,iMax);
- width=r.right-r.left;
- b=1/(g->spaceConstantAlongBars/g->degreesPerPixel);
- b*=g->checkSize; // Shrink
- fYSymmetry=kEven;
- for(i=0;i<=iMax;i++){
- a=(i+0.5)*b;
- fY[-i-1]=fY[i]=exp(-a*a);
- }
- if(g->spaceConstantAlongBars!=g->spaceConstantAcrossBars){
- b=1/(g->spaceConstantAcrossBars/g->degreesPerPixel);
- b*=g->checkSize; // Shrink
- for(i=0;i<=iMax;i++){
- a=(i+0.5)*b;
- fXEnvelope[-i-1]=fXEnvelope[i]=exp(-a*a);
- }
- }else{
- for(i=0;i<=iMax;i++) fXEnvelope[-i-1]=fXEnvelope[i]=fY[i];
- }
- assert(fYSymmetry==kEven);
- w=2*PI*g->spatialFrequency*g->degreesPerPixel;
- w*=g->checkSize; // Shrink
- e1=g->eAmplitude;
- switch(g->gratingType){
- case kCosinewave:
- fXSymmetry=kEven;
- for(i=0;i<=iMax;i++){
- fX[-i-1]=fX[i]=e1*fXEnvelope[i]*cos((i+0.5)*w);
- }
- break;
- case kSinewave:
- fXSymmetry=kOdd;
- for(i=0;i<=iMax;i++){
- fX[i]=e1*fXEnvelope[i]*sin((i+0.5)*w);
- fX[-i-1]=-fX[i];
- }
- break;
- case kSquarewave:
- fXSymmetry=kOdd;
- for(i=0;i<=iMax;i++){
- if(sin((i+0.5)*w)>=0)fX[i]=1;
- else fX[i]=-1;
- fX[i]*=e1*fXEnvelope[i];
- fX[-i-1]=-fX[i];
- }
- break;
- case kMissingFundamental:
- fXSymmetry=kOdd;
- for(i=0;i<=iMax;i++){
- a=sin((i+0.5)*w);
- fX[i]=(a>0)?1:-1;
- fX[i]-=(4/PI)*a;
- fX[i]*=e1*fXEnvelope[i];
- fX[-i-1]=-fX[i];
- }
- break;
- }
- if(!g->vertical){
- fTemp=fX;
- i=fXSymmetry;
- fX=fY;
- fXSymmetry=fYSymmetry;
- fY=fTemp;
- fYSymmetry=i;
- }
- gratingPix=lvector(-iMax-1,iMax);
- dc=g->eOffset+0.5;
- leftEdge=r.left+g->origin.h/g->checkSize;
- verticalOrigin=g->origin.v/g->checkSize;
- for(j=iMax;j>=0;j--){
- if(j>=r.bottom && -j-1<r.top)continue;
- switch(fXSymmetry){
- case kEven:
- for(i=iMax;i>=0;i--)gratingPix[-i-1]=gratingPix[i]=dc+fY[j]*fX[i];
- break;
- case kOdd:
- for(i=iMax;i>=0;i--){
- a=fY[j]*fX[i];
- gratingPix[i]=dc+a;
- gratingPix[-i-1]=dc-a;
- }
- break;
- default:
- assert(0);
- }
- if(j<r.bottom)SetPixelsQuickly(leftEdge,j+verticalOrigin,&gratingPix[r.left],width);
- if(-j-1>=r.top){
- switch(fYSymmetry){
- case kEven:
- break;
- case kOdd:
- for(i=iMax;i>=-iMax-1;i--)gratingPix[i]=dc-(gratingPix[i]-dc);
- break;
- default:
- assert(0);
- }
- SetPixelsQuickly(leftEdge,-j-1+verticalOrigin,&gratingPix[r.left],width);
- }
- }
- free_lvector(gratingPix,-iMax-1,iMax);
- free_vector(fX,-iMax-1,iMax);
- free_vector(fXEnvelope,-iMax-1,iMax);
- free_vector(fY,-iMax-1,iMax);
- }
-